import os
import subprocess
import shutil
from typing import Optional


def resolve_codeql_executable() -> str:
    env_path = os.getenv("CODEQL_CLI") or os.getenv("CODEQL_PATH")
    if env_path and os.path.isfile(env_path):
        return env_path

    # Try common names on PATH
    exe_name = "codeql.cmd" if os.name == "nt" else "codeql"
    codeql_path = shutil.which(exe_name) or shutil.which("codeql")
    if codeql_path:
        return codeql_path

    raise FileNotFoundError(
        "未找到 CodeQL 可执行文件。请设置环境变量 CODEQL_CLI 指向 codeql 可执行文件，或将其加入 PATH。"
    )


def run_callgraph_query(
    database_path: str,
    query_file: str,
    output_csv: str,
    additional_flags: Optional[list[str]] = None,
) -> None:
    codeql = resolve_codeql_executable()

    os.makedirs(os.path.dirname(os.path.abspath(output_csv)), exist_ok=True)

    cmd = [
        codeql,
        "database",
        "analyze",
        database_path,
        query_file,
        "--format=csv",
        f"--output={output_csv}",
        "--rerun",
    ]

    if additional_flags:
        cmd.extend(additional_flags)

    # Windows PowerShell 兼容执行
    completed = subprocess.run(cmd, capture_output=True, text=True)
    if completed.returncode != 0:
        raise RuntimeError(
            f"CodeQL 查询失败 (exit={completed.returncode})\nSTDOUT:\n{completed.stdout}\nSTDERR:\n{completed.stderr}"
        )

    # Basic sanity check
    if not os.path.isfile(output_csv) or os.path.getsize(output_csv) == 0:
        raise RuntimeError("未生成有效的 CSV 输出，请检查数据库与查询是否正确。")


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="运行 C++ 调用关系 CodeQL 查询")
    parser.add_argument("--db", required=True, help="CodeQL 数据库路径")
    parser.add_argument(
        "--query",
        default=os.path.join(os.path.dirname(__file__), "..", "queries", "CallGraph.ql"),
        help="查询文件路径 (默认 queries/CallGraph.ql)",
    )
    parser.add_argument("--out", required=True, help="输出 CSV 路径")
    args = parser.parse_args()

    run_callgraph_query(args.db, args.query, args.out)

